Out: Monday, March 14, 2016
Due: Monday, March 21, 2016 at 5pm local time.
Corrected: Wednesday, March 16
(examples for least-argument-yielding)
Corrected: Thursday, March 17
(added WHERE clause for least-argument-yielding)
The goal of this problem set is to give you practice using most of what you've learned this semester.
Some of these problems may not be easy, so start early and leave yourself plenty of time to finish them.
You must use DrScheme's HtDP Intermediate Student Language with
  Lambda. Use higher order functions such as
  filter and map whenever
  they are helpful. As before, you will be penalized for failing to
  use these when they are "obviously" applicable. 
Remember that you must follow the design recipe, and write invariants (as WHERE clauses) whenever an argument represents context information. We expect that your data definitions, interpretations, and invariants will be sufficient to explain the meaning of every quantity in your program. You will be judged on the adequacy of these deliverables.
For each function that you write using general recursion, you must deliver:
The example files contain numerous examples of the first three of these deliverables.
You will be judged on the correctness of your halting measures and termination arguments.
If you really need to do so, it is ok to write two mutually-recursive functions using general recursion. If you do this, you need make sure that your halting measure decreases on EVERY recursive call to the function, even if that call comes via the other function.
As before, if your function does not fulfill its purpose for all combinations of arguments that satisfy the contract, then you must write an invariant that documents what additional assumptions your function makes about its arguments.
Not everything on this problem set requires the use of invariants or the use of general recursion. Part of your task is to figure out when you need these things and when you do not. Remember, it is the purpose statement that determines whether or not you need to state an invariant.
Remember that you must follow the design recipe. Your deliverables include the data definitions (including interpretation and templates), contract and purpose header, strategies, code, and tests. Be sure to sync your work and fill out a Work Session Report at the end of every work session. Use the Work Session Report for PS08
As usual, the rubric for grading is here.
The first problem refers to the Fibonacci sequence f0, f1, f2, ... defined by
The second and third problems refer to symbols, which are just Racket symbols. You have already read about them in Part IV of the textbook.
search.rkt
that provides the following four functions:
;;; fib : NonNegInt -> NonNegInt ;;; GIVEN: i ;;; RETURNS: the Fibonacci number fi (defined above) ;;; EXAMPLES: ;;; (fib 0) => 0 ;;; (fib 10) => 55 ;;; ;;; next-fibonacci-number : Integer -> NonNegInt ;;; GIVEN: any integer n ;;; RETURNS: the smallest Fibonacci number greater than or equal to n ;;; EXAMPLES: ;;; (next-fibonacci-number -226) => 0 ;;; (next-fibonacci-number 50) => 55 ;;; ;;; least-result-as-large-as : (NonNegInt -> Integer) Integer -> Integer ;;; GIVEN: a function f and an integer n ;;; WHERE: f is monotonic ;;; RETURNS: the smallest value of (f i) such that ;;; i is a non-negative integer and (f i) is greater than or equal to n ;;; EXAMPLES: ;;; (least-result-as-large-as fib -226) => 0 ;;; (least-result-as-large-as fib 50) => 55 ;;; (least-result-as-large-as sqr 100) => 100 ;;; (least-result-as-large-as sqr 500) => 529 ;;; ;;; least-argument-yielding : (NonNegInt -> Integer) Integer -> Integer ;;; GIVEN: a function f and an integer n ;;; WHERE: there exists some non-negative integer k such that (f k) ;;; is greater than or equal to n ;;; RETURNS: the smallest value of i such that ;;; i is a non-negative integer and (f i) is greater than or equal to n ;;; EXAMPLES: ;;; (least-argument-yielding fib -226) => 0 ;;; (least-argument-yielding fib 50) => 10 ;;; (least-argument-yielding sqr 100) => 10 ;;; (least-argument-yielding sqr 500) => 23 ;;; (least-argument-yielding (lambda (i) (- (sqr i) (* 20 i))) 100) => 25
Be sure to spell the names of your functions correctly, both in their definitions and in your list of provided functions.
freevars.rkt
that provides functions to compute the free and bound variables
of programs written in a simple programming language.
That language's syntax is defined as follows:
;;; An Expr is one of ;;; -- Integer ;;; -- Symbol ;;; -- Call ;;; ;;; Interpretation: an Expr represents an integer, an identifier, ;;; or a function call. ;;; ;;; A Call is ;;; (cons Expr ListOfExpr) ;;; ;;; Interpretation: a Call represents a function call in which ;;; the value of the first expression in the Call must be a function, ;;; which is called on the values of the expressions in the ListOfExpr. ;;; ;;; A Defn is ;;; (list 'def (cons Symbol ListOfSymbol) Expr) ;;; ;;; Interpretation: a Defn represents a function. ;;; The lone Symbol is the name of the function, and the symbols ;;; in the ListOfSymbol are the names of its arguments. The Expr ;;; represents the value to be returned by the function. ;;; (Note that functions with no arguments can be defined.) ;;; ;;; A Program is ;;; (cons Defn ListOfDefn) ;;; Interpretation: a program is a non-empty list of definitions. ;;; When the program is run, the function defined by the first ;;; definition will be called with arguments obtained in some ;;; OS-dependent manner we needn't discuss here. ;;; ;;; A ListOfSymbol is ;;; -- empty ;;; -- (cons Symbol ListOfSymbol) ;;; ;;; A ListOfExpr is ;;; -- empty ;;; -- (cons Expr ListOfExpr) ;;; ;;; A ListOfDefn is ;;; -- empty ;;; -- (cons Defn ListOfDefn)
A SetOfSymbol is a ListOfSymbol
in which no symbol appears more than once.
The set of free variables of an Expr E
is the set of symbols that occur within E.
Formally:
(cons E0
                (list E1 ...
                      En)),
    then its set of free variables is the union of the sets
    of free variables for
    E0,
    E1, ... En.
The set of bound variables of a Defn of the form
    (list 'def (cons I0 (list I1 ... In))
          E)
is the set {I0,
            I1, ...
            In}.
The set of free variables of that definition is the set difference
between the set of free variables of E
and the definition's set of bound variables.
A program's set of free variables is the set difference between the union of the sets of free variables of its definitions and the set of function names defined by those definitions. A program's set of bound variables is the union of the sets of bound variables of its definitions.
Your freevars.rkt file must provide
the following nine functions:
;;; expr-free    : Expr    -> SetOfSymbol
;;; defn-free    : Defn    -> SetOfSymbol
;;; program-free : Program -> SetOfSymbol
;;; GIVEN: (respectively) an expression, definition, or program
;;; RETURNS: the set of free variables
;;;     of that expression, definition, or program
;;; EXAMPLES: see below
;;;
;;; expr-bound    : Expr    -> SetOfSymbol
;;; defn-bound    : Defn    -> SetOfSymbol
;;; program-bound : Program -> SetOfSymbol 
;;; GIVEN: (respectively) an expression, definition, or program
;;; RETURNS: the set of bound variables
;;;     of that expression, definition, or program
;;; EXAMPLES: see below
;;;
;;; expr-undefined    : Expr    SetOfSymbol -> SetOfSymbol
;;; defn-undefined    : Defn    SetOfSymbol -> SetOfSymbol
;;; program-undefined : Program SetOfSymbol -> SetOfSymbol
;;; GIVEN: (respectively) an expression, definition, or program
;;;     and a set of symbols representing the set of identifiers
;;;     that are defined by the expression's, definition's, or
;;;     program's context
;;; RETURNS: the set of free variables of that expression, definition,
;;;     or program minus the set of identifiers defined by its context
;;; EXAMPLES: see below
(define expr1 '(+ x y 3))
(define expr2 (list '* expr1 expr1 'z))
(define defn1 (list 'def '(f x y) expr2))
(define defn2 '(def (g a z) (f z a)))
(define pgm1 (list defn1 defn2))
(expr-free expr1)       ; => { +, x, y }
(expr-free expr2)       ; => { *, +, x, y, z }
(defn-free defn1)       ; => { *, +, z }
(defn-free defn2)       ; => { f }
(program-free pgm1)     ; => { *, +, z }
(expr-bound expr1)      ; => { }
(expr-bound expr2)      ; => { }
(defn-bound defn1)      ; => { f, x, y }
(defn-bound defn2)      ; => { g, a, z }
(program-bound pgm1)    ; => { a, f, g, x, y, z }
(expr-undefined expr1   '(+ - * f g x y))    ; => { }
(expr-undefined expr2   '(+ - * f g x y))    ; => { z }
(defn-undefined defn1   '(+ - * f g))        ; => { z }
(defn-undefined defn2   '(+ - * f g))        ; => { }
(program-undefined pgm1 '(+ - * f g))        ; => { z }
pretty.rkt
that defines a pretty-printer for the programming language defined
in the previous problem.
More precisely, you are to provide the following function:
;;; program-to-strings : Program PosInt -> ListOfString ;;; GIVEN: a program and a width ;;; RETURNS: a representation of the program as a sequence of lines, ;;; following the formatting rules described below
In the formatting rules below, a program fragment fits on a line if and only if a string that starts with the proper indentation for that program fragment and contains that program fragment is no longer than the given width.
(def (I0
                    I1 ...
                    In)
                    E)
        is formatted by formatting the
        "(def (I0
                     I1 ...
                     In)"
        part as described below, followed by E
        starting on a new line with an additional two spaces of
        indentation.
    (def (I0
                     I1 ...
                     In)"
        part of a definition is formatted on a single line if
        it will fit on a line no longer than the given width,
        with no indentation.
    (def (I0
                     I1"
        part will fit on a single line (with no indentation),
        and all of the
        remaining arguments will fit if placed on separate
        lines and indented so they line up under the first
        argument, and the parenthesis that closes the list
        of arguments will also fit on the line containing
        the last argument, then the function header is
        formatted that way.
    (def (I0"
        part is formatted on a single line (with no indentation),
        and every one
        of the remaining arguments is placed on a separate
        line, indented to line up under I0,
        with the parenthesis that closes the list of arguments
        on the same line as the last argument.
    (E0
               E1 ...
               En)
        will not fit within a single line when indented, but the
        "(E0
               E1"
        part will fit, then that much of the call is placed
        on a single line and each of the remaining argument
        expressions begins on a separate line, indented to
        line up under E1, and the
        closing parenthesis is placed on the same line as
        the last argument expression.
    (E0
               E1"
        part of a call will not fit within a single line when indented,
        but the "(E0" part does,
        then that much of the call expression gets a line all to itself,
        and each of the argument expressions begins on a separate line,
        indented to line up under E0.
    (E0"
        part of a call will not fit within a single line when indented,
        then E0 is formatted with one extra
        space of indentation using as many lines as necessary,
        the space immediately preceding the start of
        E0 is replaced by the opening
        parenthesis of the call, and each of the argument expressions
        begins on a separate line, indented to line up under
        E0.
    To help you debug your program, we have provided in extras.rkt the function:
;;; display-strings! : ListOfString -> Void ;;; GIVEN: a list of strings ;;; EFFECT: displays the strings on separate lines ;;; RETURNS: no value
Be sure to download a fresh copy of
extras.rkt containing this function.
Here is a sample interaction, using pgm1 as defined
in the previous problem statement:
> (display-strings! (program-to-strings pgm1 30))
(def (f x y)
  (* (+ x y 3) (+ x y 3) z))
(def (g a z)
  (f z a))
> (display-strings! (program-to-strings pgm1 25))
(def (f x y)
  (* (+ x y 3)
     (+ x y 3)
     z))
(def (g a z)
  (f z a))
Here is an example in which one line exceeds the given width:
> (display-strings! (program-to-strings pgm2 30))
(def (%vector-map1! f
                    target
                    vec
                    len)
  (loop f target vec len))
(def (loop f target vec i)
  (if (zero? i)
      target
      (let ((j (- i 1)))
           (vector-set! target
                        j
                        (f
                         (vector-ref
                          vec
                          j)))
           (loop f
                 target
                 vec
                 j))))
Here are some hints on this problem.
display-strings! is to help you to debug
    your program, but we will be testing the lists of
    strings produced by program-to-strings.number->string and
    symbol->string functions
    convert numbers and symbols to strings.Last modified: Wed Mar 16 2016